# Objects.java

    package org.codefilarete.tool.bean;

    import java.util.Arrays;
    import java.util.function.Predicate;

    import org.codefilarete.tool.function.Predicates;

    /**
     * @author Guillaume Mary
     */
    public class Objects {

    	/**
    	 * Returns an empty {@link String} if given one is null
    	 * @param value any {@link String}, null included
    	 * @return an empty {@link String} if given one is null
    	 */
    	public static String preventNull(String value) {
    		return preventNull(value, "");
    	}

    	/**
    	 * Returns nullValue if given value is null
    	 * @param value any {@link Object}, even null
    	 * @param nullValue any replacing {@link Object}
    	 * @return nullValue if given value is null
    	 * @param <E> input and output type
    	 */
    	public static <E> E preventNull(E value, E nullValue) {
    		return value == null ? nullValue : value;
    	}

    	/**
    	 * Returns a fallback value if the given input equals a matching one
    	 *
    	 * @param input value that may equal the matching one
    	 * @param matchingCase value on which fallback value will be return
    	 * @param fallbackValue value returned when input equals matching value
    	 * @param <C> type of mangaed value
    	 * @return fallbackValue if input equals matching case
    	 */
    	public static <C> C fallback(C input, C matchingCase, C fallbackValue) {
    		if (java.util.Objects.equals(input, matchingCase)) {
    			return fallbackValue;
    		} else {
    			return input;
    		}
    	}

    	/**
    	 * Static method to negate the given predicate so one can write {@code not(String::contains)}.
    	 *
    	 * @param predicate any {@link Predicate}, a method reference is preferred else this method as no purpose and can be replaced by {@link Predicate#negate}
    	 * @param <E> input type of tested elements
    	 * @return a negated {@link Predicate} of the given one
    	 */
    	public static <E> Predicate<E> not(Predicate<E> predicate) {
    		return Predicates.not(predicate);
    	}

    	/**
    	 * Returns true if the arguments are equal to each other and false otherwise. As the opposite of {@link java.util.Objects#equals(Object, Object)}
    	 * this implementation works on array since it's bounded to {@link java.util.Objects#deepEquals(Object, Object)}.
    	 *
    	 * @param a an object
    	 * @param b an object to be compared with {@code a} for equality
    	 * @return {@code true} if the arguments are equal to each other and {@code false} otherwise
    	 * @see java.util.Objects#deepEquals(Object, Object)
    	 */
    	public static boolean equals(Object a, Object b) {
    		return java.util.Objects.deepEquals(a, b);
    	}

    	/**
    	 * Returns the hash code of an object. As the opposit of {@link java.util.Objects#hashCode(Object)} or {@link java.util.Objects#hash(Object...)}
    	 * this implementation works on array since it's bounded to {@link java.util.Arrays#deepHashCode(Object[])}.
    	 *
    	 * @param o an object
    	 * @return the hash code of a non-{@code null} argument and 0 for a {@code null} argument
    	 * @see Object#hashCode
    	 * @see java.util.Arrays#deepHashCode(Object[])
    	 */
    	public static int hashCode(Object o) {
    		if (o == null) return 0;
    		if (o.getClass().isArray()) {
    			return Arrays.deepHashCode((Object[]) o);
    		} else {
    			return o.hashCode();
    		}
    	}

    	/**
    	 * Generates the hash code for a sequence of input values. As the opposit of {@link java.util.Objects#hashCode(Object)} or {@link java.util.Objects#hash(Object...)}
    	 * this implementation works on array of arrays since it's bounded to {@link java.util.Arrays#deepHashCode(Object[])}.
    	 *
    	 * @param values the values to be hashed
    	 * @return a hash value of the sequence of input values
    	 * @see Object#hashCode
    	 * @see java.util.Arrays#deepHashCode(Object[])
    	 */
    	public static int hashCode(Object... values) {
    		if (values == null) return 0;
    		int result = 0;
    		for (Object element : values)
    			result = 31 * result + hashCode(element);
    		return result;
    	}
    }